fix(interp): deftype fails at its own form with a locating error - #355
Merged
Conversation
deftype was a builtin wired to a nil stub, so (deftype T [x y]) took the function-application path, evaluated its args, and died on the unbound symbol T with "Unable to resolve symbol: T" — an error that names a symbol and points nowhere near the real cause. deftype is genuinely unimplemented (it needs mutable/volatile fields, set! over them, and array interop). Made it a special form that returns "deftype is not implemented (defining T); use defrecord where a map-backed type suffices" without evaluating its args, so the failure lands on the deftype line and says what is actually missing. Removed the unreachable builtin registration. defrecord and reify unaffected; suite 431/431.
csm
self-requested a review
August 29, 2026 04:01
andrewdean
pushed a commit
to andrewdean/clojurust
that referenced
this pull request
Sep 2, 2026
…ith tests The merge of main into upstream/deftype resolved the conflict in interp/special.rs by keeping BOTH sides of eval_deftype: a truncated copy of the new one — its body cut off after the field-spec parse and an orphan fragment of intern_type_symbol's body spliced in, referencing `globals` and `ns` that do not exist there — followed by csm#355's old "not implemented" stub. That is E0428 plus two E0425, so cljrs-runtime did not compile at all: both the WASM build and Build/test/lint went red, the WASM job on the compile errors and the lint job on rustfmt drift the same merge left behind. Three things the merges silently reverted, restored: 1. eval_deftype's body. It registers the protocol impls with the mutable field names, builds the positional ->T constructor (routing to make-type-instance-mut when the type declares mutable fields) and interns the type symbol. The duplicate stub is gone. 2. defrecord's field parse, back onto the shared parse_field_specs rather than a second hand-rolled copy. parse_field_specs now reads the vector through `as_vector`, so a marker on the field vector itself — (defrecord R ^:marker [x]) — stays transparent for deftype as it already was for defrecord. 3. resolve_protocol_sym's three call sites (PR csm#354). The merges dropped all three back to lookup_in_ns(current_ns, "mp/IThing"), leaving the helper dead — which also fails `clippy -D warnings` — and cross-namespace protocol impls broken again with "mp/IThing is not a protocol". Everything outside special.rs survived and is unchanged: TypeInstance.mutable, the serialize fold, rt_assoc, the set! lowering declines, .-field dispatch and the make-type-instance-mut builtin. Nothing caught any of this, because nothing tested the behaviour — so: - deftype_types.rs: the constructor, .-field, instance?, the absent map->T, fields in scope in a method body, multi-protocol dispatch, set! in both forms, instance independence, and mixed immutable/mutable fields. - deftype_mutable_tiered.rs: its own binary so it can force eager IR lowering process-wide. Three of its four tests fail when the set!-on-a-local decline is removed ("IR interpreter: var not found user/n"), and the immutable control still passes — the tree-walking tests cannot discriminate there. - qualified_protocol_impl.rs: all five impl sites across a namespace boundary, by alias and fully qualified, plus the same-ns control. Six of the seven fail when resolve_protocol_sym is neutered. Docs: differences.md and TODO.md said deftype is not implemented; the crate READMEs now carry TypeInstance.mutable, the shared deftype/defrecord helpers, the .-field dispatch rule and the set! lowering decline. Verified: cargo fmt --check, clippy --workspace -D warnings, cargo test --workspace, the wasm32-unknown-unknown release build, and the AOT clojure-test-suite (310 tests / 5543 assertions, 0 failures). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wdq2umKkdALhZbbGMxM8n1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
deftype was a builtin wired to a nil stub, so (deftype T [x y]) took the
function-application path, evaluated its args, and died on the unbound symbol T
with "Unable to resolve symbol: T" — an error that names a symbol and points
nowhere near the real cause. deftype is genuinely unimplemented (it needs
mutable/volatile fields, set! over them, and array interop).
Made it a special form that returns "deftype is not implemented (defining T);
use defrecord where a map-backed type suffices" without evaluating its args, so
the failure lands on the deftype line and says what is actually missing.
Removed the unreachable builtin registration. defrecord and reify unaffected;
suite 431/431.